#include "clib_tcp_misc.h"
#include "clib_sock.h"
#include "clib_stack_trace.h"
#include "clib_eth.h"
#include "clib_tcp_buffer.h"
#include "clib_tcp_fsm.h"
#include "clib_dpdk_packet.h"

//#define mbuf_type_offset(mbuf,type,offset) rte_pktmbuf_mtod_offset(mbuf,type,offset)

i32_t
tcp_send_pack(stack_ctx_t *ctx, stack_netif_t *netif, clib_sock_t *sock, u08_t flag, int32_t type)
{   

    if(netif->type == CLIB_NETIF_TYPE_DPDK) {
    
        tcp_dpdk_generate_packet(netif, sock, flag, type);
    }

    return rn_error;
}

i32_t
tcp_check_seq(stack_ctx_t *ctx, clib_sock_t *sock,tcp_hdr_t *tcp, i32_t data_len) 
{
    tcp_stream_t *stream = &sock->tcp_stream;

   //Due to zero windows and zero length segments, we have four cases for the
   //acceptability of an incoming segment (refer to RFC 793, section 3.3)
    if(data_len == 0 && stream->rcv_wnd == 0) {

        if(tcp->th_seq == stream->rcv_nxt) {
            return rn_error;
        }

    } else if (data_len == 0 && stream->rcv_wnd != 0) {
        //If segment length is zero and receive window is non zero, then test if
        //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND
        /** TODO 重新计算SEQ **/
        if(TCP_CMP_SEQ(tcp->th_seq,stream->rcv_nxt) >= 0 && \
           TCP_CMP_SEQ(tcp->th_seq,stream->rcv_nxt + stream->rcv_wnd) < 0) {
            return rn_ok;
        }

    } else if (data_len != 0 && stream->rcv_wnd == 0) {
        
        //If segment length is non zero and receive window is zero, then the
        //sequence number is not acceptable
        return rn_error;
    } else {
        //If both segment length and receive window are non zero, then test if
        //RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND or
        //RCV.NXT <= SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
        if(TCP_CMP_SEQ(tcp->th_seq,stream->rcv_nxt) >= 0 && \
           TCP_CMP_SEQ(tcp->th_seq,stream->rcv_nxt + stream->rcv_wnd) < 0) {
            return rn_ok;
        } else if (TCP_CMP_SEQ(tcp->th_seq,stream->rcv_nxt) >= 0 && \
                   TCP_CMP_SEQ(tcp->th_seq + data_len - 1,stream->rcv_nxt + stream->rcv_wnd) < 0)  {
            return rn_ok;
        } else {
            return rn_error;
        }
    }

    return rn_error;
}

i32_t
tcp_check_ack(stack_ctx_t *ctx, clib_sock_t *sock,tcp_hdr_t *tcp, i32_t data_len) 
{
    tcp_stream_t* stream = &sock->tcp_stream;

    if(TCP_CMP_ACK(tcp->ack,stream->snd_una) < 0) {
        //An old duplicate ACK has been received
        return rn_error;
    } else if(TCP_CMP_ACK(tcp->ack,stream->snd_nxt) > 0) {
        //Test the case where SEG.ACK > SND.NXT
        return rn_error;
    }
    
    /** 更新windows **/
    if(TCP_CMP_ACK(tcp->ack,stream->snd_una) >= 0) {
        stream->snd_wnd += (tcp->ack - stream->snd_una);
        stream->snd_wl2 = stream->snd_una;
        stream->snd_una = tcp->ack;
    }

    return rn_ok;
}

i32_t
tcp_get_option(stack_ctx_t *ctx, clib_sock_t *sock, u08_t *option, i32_t data_len) 
{
    return rn_error;
}

i32_t
tcp_set_option(stack_ctx_t *ctx, clib_sock_t *sock, u08_t *option, i32_t *opts_len)
{
    return rn_error;
}